/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "service_sec_storage_func.h"

#include <stddef.h>

#include <securec.h>
#include <tee_dynamic_srv.h>
#include <tee_hw_ext_api.h>

#include "logger.h"
#include "se_base_services_defines.h"

#define MAX_STORAGE_KEY_LEN 80
typedef struct SecStorageSalt {
    TEE_UUID uuid;
    uint8_t key[MAX_STORAGE_KEY_LEN];
} SecStorageSalt;

typedef struct StoragePartitionTable {
    TEE_UUID uuid;
    const char *name;
    uint8_t slotId;
} StoragePartitionTable;

ResultCode StorageKeyDerive(uint32_t sender, uint8_t *key, uint32_t len)
{
    if (key == NULL || len > MAX_STORAGE_KEY_LEN) {
        LOG_ERROR("invalid input");
        return INVALID_PARA_NULL_PTR;
    }

    SecStorageSalt salt;
    (void)memset_s(&salt, sizeof(SecStorageSalt), 0, sizeof(SecStorageSalt));

    if (tee_srv_get_uuid_by_sender(sender, &salt.uuid) != TEE_SUCCESS) {
        LOG_ERROR("tee_srv_get_uuid_by_sender error");
        return INVALID_PERM;
    }

    if (memcpy_s(salt.key, MAX_STORAGE_KEY_LEN, key, len) != EOK) {
        LOG_ERROR("memcpy key error");
        return MEM_COPY_ERR;
    }

    if (TEE_EXT_DeriveTARootKey((const uint8_t *)&salt, sizeof(SecStorageSalt), key, len) != TEE_SUCCESS) {
        LOG_ERROR("deriva key error");
        return MEM_READ_ERR;
    }

    return SUCCESS;
}

ResultCode SecStorageGetSlotIdByName(uint32_t sender, const char *name, uint8_t *slotId)
{
    if (name == NULL || slotId == NULL) {
        LOG_ERROR("invalid input");
        return INVALID_PARA_NULL_PTR;
    }

    static const StoragePartitionTable TABLE[] = {
        {PIN_AUTH_TA_UUID, "default", 1},
        {PIN_AUTH_TA_UUID, "slot0", 0},
        {PIN_AUTH_TA_UUID, "slot1", 1},
        {PIN_AUTH_TA_UUID, "slot2", 2},
        {PIN_AUTH_TA_UUID, "slot3", 3},
        {PIN_AUTH_TA_UUID, "slot4", 4},
        {PIN_AUTH_TA_UUID, "slot5", 5},
        {PIN_AUTH_TA_UUID, "slot6", 6},
        {PIN_AUTH_TA_UUID, "slot7", 7},
    };

    TEE_UUID uuid;
    (void)memset_s(&uuid, sizeof(TEE_UUID), 0, sizeof(TEE_UUID));

    if (tee_srv_get_uuid_by_sender(sender, &uuid) != TEE_SUCCESS) {
        LOG_ERROR("tee_srv_get_uuid_by_sender error");
        return INVALID_PERM;
    }

    for (uint32_t loop = 0; loop < sizeof(TABLE) / sizeof(StoragePartitionTable); loop++) {
        const StoragePartitionTable *curr = &TABLE[loop];
        if (memcmp(&uuid, &curr->uuid, sizeof(TEE_UUID)) != 0) {
            continue;
        }
        if (strcmp(name, curr->name) != 0) {
            continue;
        }
        *slotId = curr->slotId;
        LOG_INFO("name %s -> slotId %u, caller is 0x%x", name, (uint32_t)curr->slotId, uuid.timeLow);
        return SUCCESS;
    }

    LOG_ERROR("cannot get name %s, caller is 0x%x", name, uuid.timeLow);
    return INVALID_PERM;
}